package org.sciom

object ScIomSequence {
  def newSymbolWithString(state: ScIomState, value: String) = new ScIomSymbol(state, value)
}

abstract class ScIomSequence(state: ScIomState) extends ScIomObject(state) {
  tag = new ScIomTag(state, "Sequence", ScIomObject.rawClone)
  // TODO: add compare func

  def protoFinish() = {
    addImmutableMethods()
    addMutableMethods()
  }

  def size(locals: ScIomObject, m: ScIomMessage) : ScIomObject
  def at(locals: ScIomObject, m: ScIomMessage) : ScIomObject

  private def addImmutableMethods() = {
    val methodTable = List(
      ("size", (self: ScIomObject, locals: ScIomObject, m: ScIomMessage) => self match {
        case seq: ScIomSequence => seq.size(locals, m)
        case _ => self.state.error(m, "%s is of the wrong type for message '%s'", self.name, m.mname.string)
      }),
      ("at", (self: ScIomObject, locals: ScIomObject, m: ScIomMessage) => self match {
        case seq: ScIomSequence => seq.at(locals, m)
        case _ => self.state.error(m, "%s is of the wrong type for message '%s'", self.name, m.mname.string)
      })
    )
    
    addMethodTable(methodTable)
  }

  private def addMutableMethods() = {
  }
}

// Immutable Sequence
class ScIomSymbol(state: ScIomState, value: String) extends ScIomSequence(state) {
  val string = value

  override def allocate() = this

  override def equals(other: Any) = other match {
    case that: ScIomSymbol => this.string == that.string
    case _ => false
  }
  
  override def hashCode = string.hashCode
  override def toString = "ScIomSymbol[\"" + string + "\"]"

  // Io: IoSeq_rawAsUnquotedSymbol
  def rawAsUnquotedSymbol() : ScIomSymbol = {
    if(string.startsWith("\"") && string.endsWith("\"")) {
      return state.symbolWithString(string.substring(1, string.length-1))
    } else {
      return state.symbolWithString(string)
    }
  }

  def size(locals: ScIomObject, m: ScIomMessage) : ScIomObject = {
    null
  }

  def at(locals: ScIomObject, m: ScIomMessage) : ScIomObject = {
    null
  }
  
  // Io: IoSeq_rawAsUnescapedSymbol
  def rawAsUnescapedSymbol() : ScIomSymbol = {
    var getIndex = 0
    var putIndex = 0

    val length = string.length
    val str = new StringBuffer(string)

    while(getIndex < length) {
      var c = str.charAt(getIndex)
      var nextChar : Char = 0
      if(getIndex + 1 < length) {
        nextChar = str.charAt(getIndex+1)
      }

      if(c != '\\') {
        if(getIndex != putIndex) {
          str.setCharAt(putIndex, c)
        }
        putIndex += 1
      } else {
        c = nextChar

        c match {
		  case  'a' => c = 7
		  case  'b' => c = '\b'
		  case  'f' => c = '\f'
		  case  'n' => c = '\n'
		  case  'r' => c = '\r'
		  case  't' => c = '\t'
		  case  'v' => c = 11
		  case '\0' => c = '\\'
          case '0' => c = 0
          case '1' => c = 1
          case '2' => c = 2
          case '3' => c = 3
          case '4' => c = 4
          case '5' => c = 5
          case '6' => c = 6
          case '7' => c = 7
          case '8' => c = 8
          case '9' => c = 9
        }

        str.setCharAt(putIndex, c)
        getIndex += 1
        putIndex += 1
      }

      getIndex += 1
    }
    
    str.setLength(putIndex)

    state.symbolWithString(str.toString())
  }
}

// Mutable Sequence
class ScIomString(state: ScIomState, value: String) extends ScIomSequence(state) {
  val buffer = new StringBuffer(value)

  override def equals(other: Any) = other match {
    case that: ScIomString => this.buffer.toString.equals(that.buffer.toString)
    case _ => false
  }

  override def hashCode = buffer.toString.hashCode
  override def toString = "ScIomString[\"" + buffer + "\"]"

  def size(locals: ScIomObject, m: ScIomMessage) : ScIomObject = {
    null
  }

  def at(locals: ScIomObject, m: ScIomMessage) : ScIomObject = {
    null
  }
}
